package top.qitun.tian.util;

import java.security.Key;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.crypto.spec.SecretKeySpec;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;

import com.google.gson.Gson;

import cn.zhangxd.platform.common.redis.RedisRepository;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import top.qitun.bizz.client.client.entity.ClientBO;
import top.qitun.bizz.user.role.entity.Role;
import top.qitun.bizz.user.tuser.entity.TUserBO;
import top.qitun.bizz.user.userrole.entity.UserRoleBO;
import top.qitun.common.utils.StringHelper;
import top.qitun.tian.util.modal.AuthUser;

public class JsonWebTokenUtility {
	static Logger logger = LoggerFactory.getLogger(JsonWebTokenUtility.class);
	private static SignatureAlgorithm signatureAlgorithm;
	private static Key secretKey;
	/**
     * Token 类型
     */
    public static final String TOKEN_TYPE_BEARER = "Bearer";
    /**
     * 权限缓存前缀
     */
    private static final String REDIS_PREFIX_AUTH = "auth:";
    /**
     * 用户信息缓存前缀
     */
    private static final String REDIS_PREFIX_USER = "user-details:";

    /**
     * redis repository
     */
    @Autowired
    private RedisRepository redisRepository;
	static {

		// 这里不是真正安全的实践
		// 为了简单，我们存储一个静态key在这里，
		// 在真正微服务环境，这个key将会被保留在配置服务器
		signatureAlgorithm = SignatureAlgorithm.HS512;
		String encodedKey = "L7A/6zARSkK1j7Vd5SDD9pSSqZlqF7mAhiOgRbgv9Smce6tf4cJnvKOjtKPxNNnWQj+2lQEScm3XIUjhW+YVZg==";
		secretKey = deserializeKey(encodedKey);
	}

//	public String createJsonWebToken(AuthTokenDetailsDTO authTokenDetailsDTO) {
//		String token = Jwts.builder().setSubject(authTokenDetailsDTO.getUserId())
//				.claim("mobile", authTokenDetailsDTO.getMobile()).claim("roles", authTokenDetailsDTO.getRoleNames())
//				.setExpiration(authTokenDetailsDTO.getExpirationDate())
//				.signWith(getSignatureAlgorithm(), getSecretKey()).compact();
//		return token;
//	}

	private static Key deserializeKey(String encodedKey) {
		byte[] decodedKey = Base64.getDecoder().decode(encodedKey);
		Key key = new SecretKeySpec(decodedKey, getSignatureAlgorithm().getJcaName());
		return key;
	}

	private static Key getSecretKey() {
		return secretKey;
	}

	public static SignatureAlgorithm getSignatureAlgorithm() {
		return signatureAlgorithm;
	}

//	public static AuthTokenDetailsDTO parseAndValidate(String token) {
//		AuthTokenDetailsDTO authTokenDetailsDTO = null;
//		try {
//			Claims claims = Jwts.parser().setSigningKey(getSecretKey()).parseClaimsJws(token).getBody();
//			String userId = claims.getSubject();
//			String mobile = (String) claims.get("mobile");
//			List<String> roleNames = (List<String>) claims.get("roles");
//			Date expirationDate = claims.getExpiration();
//
//			authTokenDetailsDTO = new AuthTokenDetailsDTO();
//			authTokenDetailsDTO.setUserId(userId);
//			authTokenDetailsDTO.setMobile(mobile);
//			authTokenDetailsDTO.setRoleNames(roleNames);
//			authTokenDetailsDTO.setExpirationDate(expirationDate);
//		} catch (JwtException ex) {
//			System.out.println(ex);
//		}
//		return authTokenDetailsDTO;
//	}

	private String serializeKey(Key key) {
		String encodedKey = Base64.getEncoder().encodeToString(key.getEncoded());
		return encodedKey;
	}
	
	/**
     * 获取用户名
     *
     * @param token Token
     * @return String
     */
    public static String getUsernameFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims != null ? claims.getSubject() : null;
    }
    
    /**
     * 获得 Claims
     *
     * @param token Token
     * @return Claims
     */
    private static Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(token)
                .getBody();
        } catch (Exception e) {
            logger.warn("getClaimsFromToken exception", e);
            claims = null;
        }
        return claims;
    }

	public static String createJsonWebToken(TUserBO user) {
		
		Optional<List<UserRoleBO>> roleListOptional = Optional.ofNullable(user.getRoleList());
		List<String> roleNames= new ArrayList<String>();
		if(roleListOptional.isPresent()){
			roleNames = roleListOptional.get().stream().map(role->role.getRoleName()).collect(Collectors.toList());
		}
		
		String token = Jwts.builder().setSubject(user.getMobile())
				.claim("mobile", user.getMobile()).claim("roles", roleNames)
				.setExpiration(user.getExpirationDate())
				.signWith(signatureAlgorithm, secretKey).compact();
		return token;
	}
	
	/**
     * 验证 Token
     *
     * @param token Token
     * @return Boolean
     */
    public static Boolean validateToken(String token) {
    	Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
        return StringHelper.isNotEmpty(token) && !isTokenExpired(token);
    }
    
    /**
     * 获得用户信息 Json 字符串
     *
     * @param token Token
     * @return String
     */
    public static AuthUser getUserDetailsString(String token) {
    	Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
    	String userId = claims.getSubject();
		String mobile = (String) claims.get("mobile");
		AuthUser authUser = new AuthUser(userId,mobile,"",true);
		return authUser;
    }
    
    /**
     * 判断 Token 是否过期
     *
     * @param token Token
     * @return Boolean
     */
    private static Boolean isTokenExpired(String token) {
        Date expirationDate = getExpiredFromToken(token);
        return expirationDate.before(new Date());
    }
    
//    public static UserDetails getUserDetails(String token) {
//        String userDetailsString = getUserDetailsString(token);
//        if (userDetailsString != null) {
//            return new Gson().fromJson(userDetailsString, AuthUser.class);
//        }
//        return null;
//    }
    
    /**
     * 获取过期时间
     *
     * @param token Token
     * @return Date
     */
    public static Date getExpiredFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims != null ? claims.getExpiration() : null;
    }

	public static String createJsonWebToken(ClientBO user) {
		Optional<List<Role>> roleListOptional = Optional.ofNullable(user.getRoleList());
		List<String> roleNames= new ArrayList<String>();
		if(roleListOptional.isPresent()){
			roleNames = roleListOptional.get().stream().map(role->role.getRoleName()).collect(Collectors.toList());
		}
		
		String token = Jwts.builder().setSubject(""+user.getId())
				.claim("userid", user.getId()).claim("roles", roleNames)
				.setExpiration(user.getExpirationDate())
				.signWith(signatureAlgorithm, secretKey).compact();
		return token;
	}

}
